package br.unifor.lec.aco;

import java.util.ArrayList;
import java.util.List;

import br.unifor.lec.aco.graph.Grafo;
import br.unifor.lec.aco.graph.Vertice;
import br.unifor.lec.aco.util.CriarGateways;
import br.unifor.lec.aco.util.VisualizacaoJUNG;

public class ACOapp {

	public ACOapp() {
	}

	static ArrayList<Integer> Gateways = new ArrayList<Integer>();
	
	public static void main(String[] args) {
		ACOapp app = new ACOapp();
		Parameters p = new Parameters();
		Grafo g = generateGraph(p);
		app.start(p, g);
	}

	private static Grafo generateGraph(Parameters p) {
		int c = p.ladoGrid;
		List<Integer> adjacents;
		int vId;
		Vertice[] vertices = new Vertice[c * c];

		for (int i = 0; i < c; i++) {
			for (int j = 0; j < c; j++) {
				adjacents = new ArrayList<Integer>();
				vId = (i * c) + j;
				if (vId % c != 0) {
					adjacents.add((vId - 1));
				}
				if (vId % c != c - 1) {
					adjacents.add((vId + 1));
				}
				if (vId - c >= 0) {
					adjacents.add((vId - c));
				}
				if (vId + c <= (c * c) - 1) {
					adjacents.add((vId + c));
				}
				
				vertices[vId] = new Vertice(i, j, vId, adjacents);
			}
		}
		int targetVertice;
		for (int k = 0; k < (int) (c * c * p.percentTarget); k++) {
			targetVertice = (int) (Math.random() * (c * c));
			if (vertices[targetVertice].target) {
				k--;
			}else {
				vertices[targetVertice].target = true;
			}
		}

		int gatewayVertice;
		for (int k = 0; k < (int) (c * c * p.percentGateway); k++) {
			gatewayVertice = (int) (Math.random() * (c * c));
			if (vertices[gatewayVertice].target || vertices[gatewayVertice].gateway) {
				k--;
			}else {
				vertices[gatewayVertice].gateway = true;
				Gateways.add(gatewayVertice);
			}
		}

		return new Grafo(vertices);
	}

	@SuppressWarnings("unchecked")
	private void start(Parameters p, Grafo g) {
		int numVertices = g.getNumVertices();
		int[] antInicialVertice = new int[p.numAnts];

		// Gera posicao inicial das ants
		int position;
		switch (p.distribuicao) {
		case RANDOM:
			for (int i = 0; i < p.numAnts; i++) {
				position = (int) (Math.random() * numVertices);
				if (g.getVertices()[position].target
						|| !g.getVertices()[position].gateway) {
					i--;
				} else {
					antInicialVertice[i] = position;
				}
			}
			break;
		case UNIC:
			position = (int) (Math.random() * numVertices);
			while (g.getVertices()[position].target
					|| !g.getVertices()[position].gateway)
				position = (int) (Math.random() * numVertices);
			for (int i = 0; i < p.numAnts; i++) {
				antInicialVertice[i] = position;
			}
			break;
		case PL:
			List<String> posicoes = CriarGateways.criarGateways100PowerLaw();
			for (int i = 0; i < p.numAnts; i++) {
				antInicialVertice[i] = Gateways.get(new Integer(posicoes.get(i).toString()));
			}
			break;
		}

		for(int u=0; u<antInicialVertice.length;u++){
			int tmpo= g.getVertices()[antInicialVertice[u]].getNumAgentesAqui();
			tmpo++;
			g.getVertices()[antInicialVertice[u]].setNumAgentesAqui(tmpo);
		}
		
		ACO aco = new ACO(p, g, antInicialVertice);
		aco.run();
		System.out.println("Fim!");
		float soma=0, contador=0;
		for(int i=0;i<g.getNumVertices();i++) {
			if(g.getVertices()[i].gateway) {
				soma+=g.getVertices()[i].distanciaAlvos;
				contador++;
			}
		}
		System.out.println("Distancia media de um gateway ate um alvo eh de: "+(soma/contador)/(p.percentGateway*p.ladoGrid*p.ladoGrid));
		System.out.println(aco.getStatistic().print());
		
		for(Integer key :aco.getStatistic().getHash().keySet()){
			g.getVertices()[key].setNumAgentesAqui(aco.getStatistic().getHash().get(key));
		}
		
		if(p.visualizar){
			VisualizacaoJUNG vis = new VisualizacaoJUNG();
			vis.visualizar(g);
		}
		
	}
}
